home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / AbstractButton.java < prev    next >
Text File  |  1998-06-30  |  38KB  |  1,201 lines

  1. /*
  2.  * @(#)AbstractButton.java    1.77 98/06/22
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14. package com.sun.java.swing;
  15.  
  16. import java.awt.*;
  17. import java.awt.event.*;
  18. import java.awt.image.*;
  19. import java.io.Serializable;
  20. import com.sun.java.swing.event.*;
  21. import com.sun.java.swing.border.*;
  22. import com.sun.java.swing.plaf.*;
  23. import com.sun.java.accessibility.*;
  24.  
  25. /**
  26.  * Defines the common behaviors for the JButton, JToggleButton, JCheckbox,
  27.  * and the JRadioButton classes.
  28.  * <p>
  29.  * Warning: serialized objects of this class will not be compatible with
  30.  * future swing releases.  The current serialization support is appropriate 
  31.  * for short term storage or RMI between Swing1.0 applications.  It will
  32.  * not be possible to load serialized Swing1.0 objects with future releases
  33.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  34.  * baseline for the serialized form of Swing objects.
  35.  *
  36.  * @version 1.77 06/22/98
  37.  * @author Jeff Dinkins
  38.  */
  39. public abstract class AbstractButton extends JComponent implements ItemSelectable, SwingConstants {
  40.  
  41.     // *********************************
  42.     // ******* Button properties *******
  43.     // *********************************
  44.  
  45.     public static final String MODEL_CHANGED_PROPERTY = "model";
  46.     public static final String TEXT_CHANGED_PROPERTY = "text";
  47.     public static final String MNEMONIC_CHANGED_PROPERTY = "MnemonicChanged";
  48.  
  49.     // Text positioning and alignment
  50.     public static final String MARGIN_CHANGED_PROPERTY = "margin";
  51.     public static final String VERTICAL_ALIGNMENT_CHANGED_PROPERTY = "verticalAlignment";
  52.     public static final String HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY = "horizontalAlignment";
  53.  
  54.     public static final String VERTICAL_TEXT_POSITION_CHANGED_PROPERTY = "verticalTextPosition";
  55.     public static final String HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY = "horizontalTextPosition";
  56.  
  57.     // Paint options
  58.     public static final String BORDER_PAINTED_CHANGED_PROPERTY = "borderPainted";
  59.     public static final String FOCUS_PAINTED_CHANGED_PROPERTY = "focusPainted";
  60.     public static final String ROLLOVER_ENABLED_CHANGED_PROPERTY = "rolloverEnabled";
  61.  
  62.     // Icons
  63.     public static final String ICON_CHANGED_PROPERTY = "icon";
  64.  
  65.     public static final String PRESSED_ICON_CHANGED_PROPERTY = "pressedIcon";
  66.     public static final String SELECTED_ICON_CHANGED_PROPERTY = "selectedIcon";
  67.  
  68.     public static final String ROLLOVER_ICON_CHANGED_PROPERTY = "rolloverIcon";
  69.     public static final String ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY = "rolloverSelectedIcon";
  70.  
  71.     public static final String DISABLED_ICON_CHANGED_PROPERTY = "disabledIcon";
  72.     public static final String DISABLED_SELECTED_ICON_CHANGED_PROPERTY = "disabledSelectedIcon";
  73.  
  74.  
  75.     protected ButtonModel model                = null;  
  76.  
  77.     private String     text                    = ""; // for BeanBox
  78.     private Insets     margin                  = null;
  79.  
  80.     // Button icons
  81.     // PENDING(jeff) - hold icons in an array
  82.     private Icon       defaultIcon             = null;
  83.     private Icon       pressedIcon             = null;
  84.     private Icon       disabledIcon            = null;
  85.  
  86.     private Icon       selectedIcon            = null;
  87.     private Icon       disabledSelectedIcon    = null;
  88.  
  89.     private Icon       rolloverIcon            = null;
  90.     private Icon       rolloverSelectedIcon    = null;
  91.     
  92.     // Display properties
  93.     private boolean    paintBorder             = true;  
  94.     private boolean    paintFocus              = true;   
  95.     private boolean    rolloverEnabled         = false;   
  96.  
  97.     // Icon/Label Alignment
  98.     private int        verticalAlignment       = CENTER;
  99.     private int        horizontalAlignment     = CENTER;
  100.     
  101.     private int        verticalTextPosition    = CENTER;
  102.     private int        horizontalTextPosition  = RIGHT;
  103.  
  104.     /** 
  105.      * The button's model listeners.
  106.      */
  107.     protected ChangeListener changeListener = null;
  108.     protected ActionListener actionListener = null;
  109.     protected ItemListener itemListener = null;
  110.  
  111.     /**
  112.      * Only one ChangeEvent is needed per button instance since the
  113.      * event's only state is the source property.  The source of events
  114.      * generated is always "this".
  115.      */
  116.     protected transient ChangeEvent changeEvent;
  117.     
  118.     /**
  119.      * Returns the button's text.
  120.      * @see setText
  121.      */
  122.     public String getText() {
  123.         return text;
  124.     }
  125.     
  126.     /**
  127.      * Sets the button's text.
  128.      * @param t the string used to set the text
  129.      * @see getText
  130.      * @beaninfo
  131.      *        bound: true
  132.      *  description: The button's text.
  133.      */
  134.     public void setText(String text) {
  135.         String oldValue = text;
  136.         this.text = text;
  137.         firePropertyChange(TEXT_CHANGED_PROPERTY, oldValue, text);
  138.         if (accessibleContext != null) {
  139.             accessibleContext.firePropertyChange(
  140.                 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  141.                 oldValue, text);
  142.         }
  143.         invalidate();
  144.         repaint();
  145.     }
  146.  
  147.     /**
  148.      * Returns the state of the button. True if the
  149.      * toggle button is selected, false if it's not.
  150.      */
  151.     public boolean isSelected() {
  152.         return model.isSelected();
  153.     }
  154.  
  155.     /**
  156.      * Sets the state of the button.
  157.      */
  158.     public void setSelected(boolean b) {
  159.         boolean oldValue = isSelected();
  160.         if (accessibleContext != null && oldValue != b) {
  161.             if (b) {
  162.                 accessibleContext.firePropertyChange(
  163.                     AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
  164.                     null, AccessibleState.SELECTED);
  165.             } else {
  166.                 accessibleContext.firePropertyChange(
  167.                     AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
  168.                     AccessibleState.SELECTED, null);
  169.             }
  170.         }
  171.         model.setSelected(b);
  172.     }
  173.  
  174.     /**
  175.      * Programatically perform a "click". This does the same
  176.      * thing as if the user had pressed and released the button.
  177.      */
  178.     public void doClick() {
  179.         doClick(68);
  180.     }
  181.  
  182.     /**
  183.      * Programatically perform a "click". This does the same
  184.      * thing as if the user had pressed and released the button.
  185.      * The button stays visually "pressed" for pressTime milliseconds.
  186.      */
  187.     public void doClick(int pressTime) {
  188.         Dimension size = getSize();
  189.         model.setArmed(true);
  190.         model.setPressed(true);
  191.         paintImmediately(new Rectangle(0,0, size.width, size.height));
  192.         try {
  193.             Thread.currentThread().sleep(pressTime);
  194.         } catch(InterruptedException ie) {
  195.         }
  196.         model.setPressed(false);
  197.         model.setArmed(false);
  198.     }
  199.  
  200.     /**
  201.      * Sets space for margin between the button's border and
  202.      * the label. Setting to null will cause the button to
  203.      * use the default margin.  The button's default Border
  204.      * object will use this value to create the proper margin.
  205.      * However, if a non-default border is set on the button, 
  206.      * it is that Border object's responsibility to create the
  207.      * appropriate margin space (else this property will
  208.      * effectively be ignored).
  209.      *
  210.      * @param m the space between the border and the label
  211.      *
  212.      * @beaninfo
  213.      *        bound: true
  214.      *  description: The space between the button's border and the label.
  215.      */
  216.     public void setMargin(Insets m) {
  217.         Insets old = margin;
  218.         margin = m;
  219.         firePropertyChange(MARGIN_CHANGED_PROPERTY, old, m);
  220.         invalidate();
  221.     }
  222.  
  223.     /**
  224.      * Returns the margin between the button's border and
  225.      * the label.
  226.      */
  227.     public Insets getMargin() {
  228.         if(margin == null) {
  229.             return ((ButtonUI)ui).getDefaultMargin(this);
  230.         } else {
  231.             return margin;
  232.         }
  233.     }
  234.  
  235.     /**
  236.      * Returns the default icon.
  237.      * @see setIcon
  238.      */
  239.     public Icon getIcon() {
  240.         return defaultIcon;
  241.     }
  242.     
  243.     /**
  244.      * Sets the button's default icon. This icon is
  245.      * also used as the "pressed" and "disabled" icon if
  246.      * there is no explicitly set pressed icon.
  247.      * @param g the icon used as the default image
  248.      * @see getIcon
  249.      * @see setPressedIcon
  250.      * @beaninfo 
  251.      *     bound: true
  252.      *     description: The button's default icon
  253.      */
  254.     public void setIcon(Icon defaultIcon) {
  255.         Icon oldValue = this.defaultIcon;
  256.         this.defaultIcon = defaultIcon;
  257.         firePropertyChange(ICON_CHANGED_PROPERTY, oldValue, defaultIcon);
  258.         if (accessibleContext != null) {
  259.             accessibleContext.firePropertyChange(
  260.                 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  261.                 oldValue, defaultIcon);
  262.         }
  263.         invalidate();
  264.         repaint();
  265.     }
  266.     
  267.     /**
  268.      * Returns the pressed icon for the button.
  269.      * @see setPressedIcon
  270.      */
  271.     public Icon getPressedIcon() {
  272.         return pressedIcon;
  273.     }
  274.     
  275.     /**
  276.      * Sets the pressed icon for the button.
  277.      * @param g the icon used as the "pressed" image
  278.      * @see getPressedIcon
  279.      * @beaninfo
  280.      *        bound: true
  281.      *  description: The pressed icon for the button.
  282.      */
  283.     public void setPressedIcon(Icon pressedIcon) {
  284.         Icon oldValue = this.pressedIcon;
  285.         this.pressedIcon = pressedIcon;
  286.         firePropertyChange(PRESSED_ICON_CHANGED_PROPERTY, oldValue, pressedIcon);
  287.         if (accessibleContext != null) {
  288.             accessibleContext.firePropertyChange(
  289.                 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  290.                 oldValue, defaultIcon);
  291.         }
  292.         invalidate();
  293.         repaint();
  294.     }
  295.  
  296.     /**
  297.      * Returns the selected icon for the button.
  298.      * @see setSelectedIcon
  299.      */
  300.     public Icon getSelectedIcon() {
  301.         return selectedIcon;
  302.     }
  303.     
  304.     /**
  305.      * Sets the selected icon for the button.
  306.      * @param g the icon used as the "selected" image
  307.      * @see getSelectedIcon
  308.      * @beaninfo
  309.      *        bound: true
  310.      *  description: The selected icon for the button.
  311.      */
  312.     public void setSelectedIcon(Icon selectedIcon) {
  313.         Icon oldValue = this.selectedIcon;
  314.         this.selectedIcon = selectedIcon;
  315.         firePropertyChange(SELECTED_ICON_CHANGED_PROPERTY, oldValue, selectedIcon);
  316.         if (accessibleContext != null) {
  317.             accessibleContext.firePropertyChange(
  318.                 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  319.                 oldValue, selectedIcon);
  320.         }
  321.         invalidate();
  322.         repaint();
  323.     }
  324.  
  325.     /**
  326.      * Returns the rollover icon for the button.
  327.      * @see setRolloverIcon
  328.      */
  329.     public Icon getRolloverIcon() {
  330.         return rolloverIcon;
  331.     }
  332.     
  333.     /**
  334.      * Sets the rollover icon for the button.
  335.      * @param g the icon used as the "rollover" image
  336.      * @see getRolloverIcon
  337.      * @beaninfo
  338.      *        bound: true
  339.      *  description: The rollover icon for the button.
  340.      */
  341.     public void setRolloverIcon(Icon rolloverIcon) {
  342.         Icon oldValue = this.rolloverIcon;
  343.         this.rolloverIcon = rolloverIcon;
  344.         firePropertyChange(ROLLOVER_ICON_CHANGED_PROPERTY, oldValue, rolloverIcon);
  345.         if (accessibleContext != null) {
  346.             accessibleContext.firePropertyChange(
  347.                 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  348.                 oldValue, rolloverIcon);
  349.         }
  350.         setRolloverEnabled(true);
  351.         invalidate();
  352.         repaint();
  353.     }
  354.     
  355.     /**
  356.      * Returns the rollover seletion icon for the button.
  357.      * @see setRolloverSelectedIcon
  358.      */
  359.     public Icon getRolloverSelectedIcon() {
  360.         return rolloverSelectedIcon;
  361.     }
  362.     
  363.     /**
  364.      * Sets the rollover selected icon for the button.
  365.      * @param g the icon used as the "selected rollover" image
  366.      * @see getRolloverSelectedIcon
  367.      * @beaninfo
  368.      *        bound: true
  369.      *  description: The rollover selected icon for the button.
  370.      */
  371.     public void setRolloverSelectedIcon(Icon rolloverSelectedIcon) {
  372.         Icon oldValue = this.rolloverSelectedIcon;
  373.         this.rolloverSelectedIcon = rolloverSelectedIcon;
  374.         firePropertyChange(ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY, oldValue, rolloverSelectedIcon);
  375.         if (accessibleContext != null) {
  376.             accessibleContext.firePropertyChange(
  377.                 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  378.                 oldValue, rolloverSelectedIcon);
  379.         }
  380.         invalidate();
  381.         repaint();
  382.     }
  383.     
  384.     /**
  385.      * Returns the icon used by the button when it's disabled.
  386.      * If not no disabled icon has been set, the button constructs
  387.      * one from the default icon. 
  388.      * PENDING(jeff): the disabled icon really should be created 
  389.      * (if necesary) by the L&F.
  390.      * @see getPressedIcon
  391.      * @see setDisabledIcon
  392.      */
  393.     public Icon getDisabledIcon() {
  394.         if(disabledIcon == null) {
  395.             if(defaultIcon != null
  396.                && defaultIcon instanceof ImageIcon) {
  397.                 disabledIcon = new ImageIcon(
  398.                     GrayFilter.createDisabledImage(
  399.                         ((ImageIcon)defaultIcon).getImage()));
  400.             }
  401.         }
  402.         return disabledIcon;
  403.     }
  404.     
  405.     /**
  406.      * Sets the disabled icon for the button.
  407.      * @param g the icon used as the disabled image
  408.      * @see getDisabledIcon
  409.      * @beaninfo
  410.      *        bound: true
  411.      *  description: The disabled icon for the button.
  412.      */
  413.     public void setDisabledIcon(Icon disabledIcon) {
  414.         Icon oldValue = this.disabledIcon;
  415.         this.disabledIcon = disabledIcon;
  416.         firePropertyChange(DISABLED_ICON_CHANGED_PROPERTY, oldValue, disabledIcon);
  417.         if (accessibleContext != null) {
  418.             accessibleContext.firePropertyChange(
  419.                 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  420.                 oldValue, disabledIcon);
  421.         }
  422.         invalidate();
  423.         repaint();
  424.     }
  425.     
  426.     /**
  427.      * Returns the icon used by the button when it's disabled and selected.
  428.      * If not no disabled selection icon has been set, the button constructs
  429.      * one from the selection icon. 
  430.      * PENDING(jeff): the disabled selection icon really should be created 
  431.      * (if necesary) by the L&F.
  432.      * @see getPressedIcon
  433.      * @see setDisabledIcon
  434.      */
  435.     public Icon getDisabledSelectedIcon() {
  436.         if(disabledSelectedIcon == null) {
  437.             if(selectedIcon != null && selectedIcon instanceof ImageIcon) {
  438.                 disabledSelectedIcon = new ImageIcon(
  439.                     GrayFilter.createDisabledImage(((ImageIcon)selectedIcon).getImage()));
  440.             } else {
  441.                 return disabledIcon;
  442.             }
  443.         }
  444.         return disabledSelectedIcon;
  445.     }
  446.  
  447.     /**
  448.      * Sets the disabled selection icon for the button.
  449.      * @param g the icon used as the disabled selection image
  450.      * @see getDisabledSelectedIcon
  451.      */
  452.     public void setDisabledSelectedIcon(Icon disabledSelectedIcon) {
  453.         Icon oldValue = this.disabledSelectedIcon;
  454.         this.disabledSelectedIcon = disabledSelectedIcon;
  455.         firePropertyChange(DISABLED_SELECTED_ICON_CHANGED_PROPERTY, oldValue, disabledSelectedIcon);
  456.         if (accessibleContext != null) {
  457.             accessibleContext.firePropertyChange(
  458.                 AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
  459.                 oldValue, disabledSelectedIcon);
  460.         }
  461.         invalidate();
  462.         repaint();
  463.     }
  464.  
  465.     /**
  466.      * Returns the vertical alignment of the text and icon.
  467.      * Valid keys: CENTER (the default), TOP, BOTTOM
  468.      */
  469.     public int getVerticalAlignment() {
  470.         return verticalAlignment;
  471.     }
  472.     
  473.     /**
  474.      * Sets the vertical alignment of the icon and text.
  475.      * Valid keys: CENTER (the default), TOP, BOTTOM
  476.      * @beaninfo
  477.      *        bound: true
  478.      *  description: The vertical alignment of the icon and text.
  479.      */
  480.     public void setVerticalAlignment(int alignment) {
  481.         if (alignment == verticalAlignment) return;
  482.         int oldValue = verticalAlignment;
  483.         verticalAlignment = checkVerticalKey(alignment, "verticalAlignment");
  484.         firePropertyChange(VERTICAL_ALIGNMENT_CHANGED_PROPERTY, oldValue, verticalAlignment);   
  485.         invalidate();
  486.         repaint();
  487.     }
  488.     
  489.     /**
  490.      * Returns the horizontal alignment of the icon and text.
  491.      * Valid keys: CENTER (the default), LEFT, RIGHT
  492.      */
  493.     public int getHorizontalAlignment() {
  494.         return horizontalAlignment;
  495.     }
  496.     
  497.     /**
  498.      * Sets the horizontal alignment of the icon and text.
  499.      * Valid keys: CENTER (the default), LEFT, RIGHT
  500.      * @beaninfo
  501.      *        bound: true
  502.      *  description: The horizontal alignment of the icon and text.
  503.      */
  504.     public void setHorizontalAlignment(int alignment) {
  505.         if (alignment == horizontalAlignment) return;
  506.         int oldValue = horizontalAlignment;
  507.         horizontalAlignment = checkHorizontalKey(alignment, "horizontalAlignment");
  508.         firePropertyChange(HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY, oldValue, horizontalAlignment);       
  509.         invalidate();
  510.         repaint();
  511.     }
  512.  
  513.     
  514.     /**
  515.      * Returns the vertical position of the text relative to the icon
  516.      * Valid keys: CENTER (the default), TOP, BOTTOM
  517.      */
  518.     public int getVerticalTextPosition() {
  519.         return verticalTextPosition;
  520.     }
  521.     
  522.     /**
  523.      * Sets the vertical position of the text relative to the icon.
  524.      * Valid keys: CENTER (the default), TOP, BOTTOM
  525.      * @beaninfo
  526.      *        bound: true
  527.      *  description: The vertical position of the text relative to the icon.
  528.      */
  529.     public void setVerticalTextPosition(int textPosition) {
  530.         if (textPosition == verticalTextPosition) return;
  531.         int oldValue = verticalTextPosition;
  532.         verticalTextPosition = checkVerticalKey(textPosition, "verticalTextPosition");
  533.         firePropertyChange(VERTICAL_TEXT_POSITION_CHANGED_PROPERTY, oldValue, verticalTextPosition);
  534.         invalidate();
  535.         repaint();
  536.     }
  537.     
  538.     /**
  539.      * Sets the horizontal position of the text relative to the icon.
  540.      * Valid keys: RIGHT (the default), LEFT, CENTER
  541.      */
  542.     public int getHorizontalTextPosition() {
  543.         return horizontalTextPosition;
  544.     }
  545.     
  546.     /**
  547.      * Sets the horizontal position of the text relative to the icon.
  548.      * Valid keys: RIGHT (the default), LEFT, CENTER
  549.      * @beaninfo
  550.      *        bound: true
  551.      *  description: The horizontal position of the text relative to the icon.
  552.      */
  553.     public void setHorizontalTextPosition(int textPosition) {
  554.         if (textPosition == horizontalTextPosition) return;
  555.         int oldValue = horizontalTextPosition;
  556.         horizontalTextPosition = checkHorizontalKey(textPosition, "horizontalTextPosition");
  557.         firePropertyChange(HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY, oldValue, horizontalTextPosition);
  558.         invalidate();
  559.         repaint();
  560.     }
  561.     
  562.     /**
  563.      * Ensures that the key is a valid. Throws an IllegalArgument exception
  564.      * exception otherwise.
  565.      */
  566.     protected int checkHorizontalKey(int key, String exception) {
  567.         if ((key == LEFT) || (key == CENTER) || (key == RIGHT)) {
  568.             return key;
  569.         } else {
  570.             throw new IllegalArgumentException(exception);
  571.         }
  572.     }
  573.     
  574.     /**
  575.      * Ensures that the key is a valid. Throws an IllegalArgument exception
  576.      * exception otherwise.
  577.      */
  578.     protected int checkVerticalKey(int key, String exception) {
  579.         if ((key == TOP) || (key == CENTER) || (key == BOTTOM)) {
  580.             return key;
  581.         } else {
  582.             throw new IllegalArgumentException(exception);
  583.         }
  584.     }
  585.     
  586.     /**
  587.      * Sets the action command for this button. 
  588.      */
  589.     public void setActionCommand(String actionCommand) {
  590.         getModel().setActionCommand(actionCommand);
  591.     }
  592.     
  593.     /**
  594.      * Returns the action command for this button. 
  595.      */
  596.     public String getActionCommand() {
  597.         String ac = getModel().getActionCommand();
  598.         if(ac == null) {
  599.             ac = getText();
  600.         }
  601.         return ac;
  602.     }
  603.     
  604.     /**
  605.      * Returns whether the border should be painted.
  606.      * @see setBorderPainted
  607.      */
  608.     public boolean isBorderPainted() {
  609.         return paintBorder;
  610.     }
  611.     
  612.     /**
  613.      * Sets whether the border should be painted.
  614.      * @param b if true and border property is not null, the border is painted.
  615.      * @see isBorderPainted
  616.      * @beaninfo
  617.      *        bound: true
  618.      *  description: Whether the border should be painted.
  619.      */
  620.     public void setBorderPainted(boolean b) {
  621.         boolean oldValue = paintBorder;
  622.         paintBorder = b;
  623.         firePropertyChange(BORDER_PAINTED_CHANGED_PROPERTY, oldValue, paintBorder);
  624.         invalidate();
  625.         repaint();
  626.     }
  627.  
  628.     /**
  629.      * Paint the button's border if BorderPainted property is true.
  630.      * 
  631.      * @see #paint
  632.      * @see #setBorder
  633.      */
  634.     protected void paintBorder(Graphics g) {    
  635.         if (isBorderPainted()) {
  636.             super.paintBorder(g);
  637.         }
  638.     }
  639.  
  640.     /**
  641.      * Returns whether focus should be painted.
  642.      * @see setFocusPainted
  643.      */
  644.     public boolean isFocusPainted() {
  645.         return paintFocus;
  646.     }
  647.     
  648.     /**
  649.      * Sets whether focus should be painted.
  650.      * @param b if true, the focus state is painted.
  651.      * @see isFocusPainted
  652.      * @beaninfo
  653.      *        bound: true
  654.      *  description: Whether focus should be painted
  655.      */
  656.     public void setFocusPainted(boolean b) {
  657.         boolean oldValue = paintFocus;
  658.         paintFocus = b;
  659.         firePropertyChange(FOCUS_PAINTED_CHANGED_PROPERTY, oldValue, paintFocus);
  660.         invalidate();
  661.         repaint();
  662.     }
  663.  
  664.     /**
  665.      * Checks whether rollover effects are enabled.
  666.      * @see setFocusPainted
  667.      */
  668.     public boolean isRolloverEnabled() {
  669.         return rolloverEnabled;
  670.     }
  671.     
  672.     /**
  673.      * Sets whether rollover effects should be enabled.
  674.      * @param b if true, rollover effects should be painted.
  675.      * @see isRolloverEnabled
  676.      * @beaninfo
  677.      *        bound: true
  678.      *  description: Whether rollover effects should be enabled.
  679.      */
  680.     public void setRolloverEnabled(boolean b) {
  681.         boolean oldValue = rolloverEnabled;
  682.         rolloverEnabled = b;
  683.         firePropertyChange(ROLLOVER_ENABLED_CHANGED_PROPERTY, oldValue, rolloverEnabled);
  684.         invalidate();
  685.         repaint();
  686.     }
  687.  
  688.     /**
  689.      * Get the keyboard mnemonic from the the current model 
  690.      */
  691.     public int getMnemonic() {
  692.         return model.getMnemonic();
  693.     }
  694.  
  695.     /**
  696.      * Set the keyboard mnemonic on the current model
  697.      * @param mnemonic the key code which represents the mnemonic
  698.      */
  699.     public void setMnemonic(int mnemonic) {
  700.     int oldValue = getMnemonic();
  701.     model.setMnemonic(mnemonic);
  702.         firePropertyChange(MNEMONIC_CHANGED_PROPERTY, oldValue, mnemonic);
  703.         invalidate();
  704.         repaint();
  705.     }
  706.  
  707.     public void setMnemonic(char mnemonic) {
  708.         int vk = (int) mnemonic;
  709.         if(vk >= 'a' && vk <='z')
  710.             vk -= ('a' - 'A');
  711.         setMnemonic(vk);
  712.     }
  713.  
  714.     /**
  715.      * Get the model that this button represents.
  716.      * @see setModel
  717.      */
  718.     public ButtonModel getModel() {
  719.         return model;
  720.     }
  721.     
  722.     /**
  723.      * Set the model that this button represents.
  724.      * @param m the Model
  725.      * @see getModel
  726.      * @beaninfo
  727.      *        bound: true
  728.      *  description: Model that the Button uses.
  729.      */
  730.     public void setModel(ButtonModel newModel) {
  731.         
  732.         ButtonModel oldModel = getModel();
  733.         
  734.         if (oldModel != null) {
  735.             oldModel.removeChangeListener(changeListener);
  736.             oldModel.removeActionListener(actionListener);
  737.             changeListener = null;
  738.             actionListener = null;
  739.         }
  740.         
  741.         model = newModel;
  742.         
  743.         if (newModel != null) {
  744.             changeListener = createChangeListener();
  745.             actionListener = createActionListener();
  746.             itemListener = createItemListener();
  747.             newModel.addChangeListener(changeListener);
  748.             newModel.addActionListener(actionListener);
  749.             newModel.addItemListener(itemListener);
  750.         }
  751.  
  752.         firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel);
  753.         invalidate();
  754.         repaint();
  755.     }
  756.  
  757.     
  758.     /**
  759.      * Returns the button's current UI.
  760.      * @see setUI
  761.      */
  762.     public ButtonUI getUI() {
  763.         return (ButtonUI) ui;
  764.     }
  765.  
  766.     
  767.     /**
  768.      * Sets the button's UI.
  769.      * @param ui the new ButtonUI
  770.      * @see getUI
  771.      */
  772.     public void setUI(ButtonUI ui) {
  773.         super.setUI(ui);
  774.     }
  775.  
  776.     
  777.     /**
  778.      * Gets a new UI object from the default UIFactory. Subtypes of
  779.      * AbstractButton should override this to update the UI. For
  780.      * example, JButton might do the following:
  781.      *      setUI((ButtonUI)UIManager.getUI(
  782.      *          "ButtonUI", "com.sun.java.swing.plaf.basic.BasicButtonUI", this));
  783.      */
  784.     public void updateUI() {
  785.     }
  786.     
  787.     /**
  788.      * Adds a ChangeListener to the button.
  789.      */
  790.     public void addChangeListener(ChangeListener l) {
  791.         listenerList.add(ChangeListener.class, l);
  792.     }
  793.     
  794.     /**
  795.      * Removes a ChangeListener from the button.
  796.      */
  797.     public void removeChangeListener(ChangeListener l) {
  798.         listenerList.remove(ChangeListener.class, l);
  799.     }
  800.     
  801.     /*
  802.      * Notify all listeners that have registered interest for
  803.      * notification on this event type.  The event instance 
  804.      * is lazily created using the parameters passed into 
  805.      * the fire method.
  806.      * @see EventListenerList
  807.      */
  808.     protected void fireStateChanged() {
  809.         // Guaranteed to return a non-null array
  810.         Object[] listeners = listenerList.getListenerList();
  811.         // Process the listeners last to first, notifying
  812.         // those that are interested in this event
  813.         for (int i = listeners.length-2; i>=0; i-=2) {
  814.             if (listeners[i]==ChangeListener.class) {
  815.                 // Lazily create the event:
  816.                 if (changeEvent == null)
  817.                     changeEvent = new ChangeEvent(this);
  818.                 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
  819.             }          
  820.         }
  821.     }   
  822.  
  823.     /**
  824.      * adds an ActionListener to the button
  825.      */
  826.     public void addActionListener(ActionListener l) {
  827.         listenerList.add(ActionListener.class, l);
  828.     }
  829.     
  830.     /**
  831.      * removes an ActionListener from the button
  832.      */
  833.     public void removeActionListener(ActionListener l) {
  834.         listenerList.remove(ActionListener.class, l);
  835.     }
  836.     
  837.     
  838.     /**
  839.      * Subclasses that want to handle ChangeEvents differently
  840.      * can override this to return another ChangeListener implementation.
  841.      */
  842.     protected ChangeListener createChangeListener() {
  843.         return (ChangeListener) new ButtonChangeListener();
  844.     }
  845.  
  846.     /**
  847.      * Extend ChangeListener to be serializable
  848.      * <p>
  849.      * Warning: serialized objects of this class will not be compatible with
  850.      * future swing releases.  The current serialization support is appropriate
  851.      * for short term storage or RMI between Swing1.0 applications.  It will
  852.      * not be possible to load serialized Swing1.0 objects with future releases
  853.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  854.      * baseline for the serialized form of Swing objects.
  855.      */
  856.     protected class ButtonChangeListener implements ChangeListener, Serializable {
  857.         ButtonChangeListener() {
  858.         }
  859.  
  860.         public void stateChanged(ChangeEvent e) {
  861.             fireStateChanged();
  862.             repaint();
  863.         }
  864.     }
  865.  
  866.  
  867.     /*
  868.      * Notify all listeners that have registered interest for
  869.      * notification on this event type.  The event instance 
  870.      * is lazily created using the parameters passed into 
  871.      * the fire method.
  872.      * @see EventListenerList
  873.      */
  874.     protected void fireActionPerformed(ActionEvent event) {
  875.         // Guaranteed to return a non-null array
  876.         Object[] listeners = listenerList.getListenerList();
  877.         ActionEvent e = null;
  878.         // Process the listeners last to first, notifying
  879.         // those that are interested in this event
  880.         for (int i = listeners.length-2; i>=0; i-=2) {
  881.             if (listeners[i]==ActionListener.class) {
  882.                 // Lazily create the event:
  883.                 if (e == null) {
  884.                     e = new ActionEvent(AbstractButton.this,
  885.                                         ActionEvent.ACTION_PERFORMED,
  886.                                         getActionCommand(),
  887.                     event.getModifiers());
  888.                 }
  889.                 ((ActionListener)listeners[i+1]).actionPerformed(e);
  890.             }          
  891.         }
  892.     }
  893.     
  894.     /*
  895.      * Notify all listeners that have registered interest for
  896.      * notification on this event type.  The event instance 
  897.      * is lazily created using the parameters passed into 
  898.      * the fire method.
  899.      * @see EventListenerList
  900.      */
  901.     protected void fireItemStateChanged(ItemEvent event) {
  902.         // Guaranteed to return a non-null array
  903.         Object[] listeners = listenerList.getListenerList();
  904.         ItemEvent e = null;
  905.         // Process the listeners last to first, notifying
  906.         // those that are interested in this event
  907.         for (int i = listeners.length-2; i>=0; i-=2) {
  908.             if (listeners[i]==ItemListener.class) {
  909.                 // Lazily create the event:
  910.                 if (e == null) {
  911.                     e = new ItemEvent(AbstractButton.this,
  912.                                       ItemEvent.ITEM_STATE_CHANGED,
  913.                                       AbstractButton.this,
  914.                                       event.getStateChange());
  915.                 }
  916.                 ((ItemListener)listeners[i+1]).itemStateChanged(e);
  917.             }          
  918.         }
  919.     }
  920.     
  921.  
  922.     private class ForwardActionEvents implements ActionListener, Serializable {
  923.         public void actionPerformed(ActionEvent event) {
  924.             fireActionPerformed(event);
  925.         }
  926.     }
  927.  
  928.     protected ActionListener createActionListener() {
  929.         return new ForwardActionEvents();
  930.     }
  931.  
  932.  
  933.     private class ForwardItemEvents implements ItemListener, Serializable {
  934.         public void itemStateChanged(ItemEvent event) {
  935.             fireItemStateChanged(event);
  936.         }
  937.     }
  938.  
  939.     protected ItemListener createItemListener() {
  940.         return new ForwardItemEvents();
  941.     }
  942.  
  943.     
  944.     /**
  945.      * Enables (or disables) the button.
  946.      */
  947.     public void setEnabled(boolean b) {
  948.         super.setEnabled(b);
  949.         model.setEnabled(b);
  950.     }
  951.  
  952.     // *** Deprecated java.awt.Button APIs below *** //
  953.     
  954.     /**
  955.      * @deprecated - Replaced by getText()
  956.      */
  957.     public String getLabel() {
  958.         return getText();
  959.     }
  960.     
  961.     /**
  962.      * @deprecated - Replaced by setText(text)
  963.      * @beaninfo
  964.      *        bound: true
  965.      *  description: Replace by setText(text)
  966.      */
  967.     public void setLabel(String label) {
  968.         setText(label);
  969.     }
  970.  
  971.     /**
  972.      * adds an ItemListener to the checkbox
  973.      */
  974.     public void addItemListener(ItemListener l) {
  975.         listenerList.add(ItemListener.class, l);
  976.     }
  977.     
  978.     /**
  979.      * removes an ItemListener from the button
  980.      */
  981.     public void removeItemListener(ItemListener l) {
  982.         listenerList.remove(ItemListener.class, l);
  983.     }
  984.  
  985.     public Object[] getSelectedObjects() {
  986.         // REMINDER: finish
  987.         return null; 
  988.     }
  989.  
  990.     protected void init(String text, Icon icon) {
  991.         setLayout(new OverlayLayout(this));
  992.  
  993.         if(text != null) {
  994.             setText(text);
  995.         }
  996.         
  997.         if(icon != null) {
  998.             setIcon(icon);
  999.         }
  1000.         
  1001.         // Set the UI
  1002.         updateUI();
  1003.         
  1004.         // Listen for Focus events
  1005.         addFocusListener(
  1006.             new FocusListener() {
  1007.             public void focusGained(FocusEvent event) {
  1008.                 if (accessibleContext != null) {
  1009.                     accessibleContext.firePropertyChange(
  1010.                         AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
  1011.                         null, AccessibleState.FOCUSED);
  1012.                 }
  1013.             }
  1014.             public void focusLost(FocusEvent event) {
  1015.                 if (accessibleContext != null) {
  1016.                     accessibleContext.firePropertyChange(
  1017.                         AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
  1018.                         null, AccessibleState.FOCUSED);
  1019.                 }
  1020.                 // repaint focus is lost
  1021.                 if(isFocusPainted()) {
  1022.                     repaint();
  1023.                 }
  1024.             }
  1025.         }
  1026.         );
  1027.  
  1028.         setAlignmentX(LEFT_ALIGNMENT);
  1029.     }
  1030.  
  1031. ///////////////////
  1032. // Accessibility support
  1033. ///////////////////
  1034.     /**
  1035.      * Accessiblity support.
  1036.      * <p>
  1037.      * Warning: serialized objects of this class will not be compatible with
  1038.      * future swing releases.  The current serialization support is appropriate
  1039.      * for short term storage or RMI between Swing1.0 applications.  It will
  1040.      * not be possible to load serialized Swing1.0 objects with future releases
  1041.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  1042.      * baseline for the serialized form of Swing objects.
  1043.      */
  1044.     protected abstract class AccessibleAbstractButton
  1045.         extends AccessibleJComponent implements AccessibleAction, 
  1046.     AccessibleValue {
  1047.  
  1048.         /**
  1049.          * Get the accessible name of this object.  
  1050.          *
  1051.          * @return the localized name of the object -- can be null if this 
  1052.          * object does not have a name
  1053.          */
  1054.         public String getAccessibleName() {
  1055.             if (accessibleName != null) {
  1056.                 return accessibleName;
  1057.             } else {
  1058.                 if (getText() == null) {
  1059.                     return super.getAccessibleName();
  1060.                 } else {
  1061.                     return getText();
  1062.                 }
  1063.             }
  1064.         }
  1065.  
  1066.         /**
  1067.          * Get the state set of this object.
  1068.          *
  1069.          * @return an instance of AccessibleState containing the current state 
  1070.          * of the object
  1071.          * @see AccessibleState
  1072.          */
  1073.         public AccessibleStateSet getAccessibleStateSet() {
  1074.         AccessibleStateSet states = super.getAccessibleStateSet();
  1075.             if (getModel().isArmed()) {
  1076.                 states.add(AccessibleState.ARMED);
  1077.             }
  1078.             if (hasFocus()) {
  1079.                 states.add(AccessibleState.FOCUSED);
  1080.             }
  1081.             if (getModel().isPressed()) {
  1082.                 states.add(AccessibleState.PRESSED);
  1083.             }
  1084.             if (isSelected()) {
  1085.                 states.add(AccessibleState.CHECKED);
  1086.             }
  1087.             return states;
  1088.         }
  1089.  
  1090.         /**
  1091.          * Get the AccessibleAction associated with this object if one
  1092.          * exists.  Otherwise return null.
  1093.          */
  1094.         public AccessibleAction getAccessibleAction() {
  1095.             return this;
  1096.     }
  1097.  
  1098.         /**
  1099.          * Get the AccessibleValue associated with this object if one
  1100.          * exists.  Otherwise return null.
  1101.          */
  1102.         public AccessibleValue getAccessibleValue() {
  1103.             return this;
  1104.         }
  1105.  
  1106.         /**
  1107.          * Returns the number of Actions available in this object.
  1108.          * If there is more than one, the first one is the "default"
  1109.          * action.
  1110.          *
  1111.          * @return the number of Actions in this object
  1112.          */
  1113.         public int getAccessibleActionCount() {
  1114.             return 1;
  1115.         }
  1116.     
  1117.         /**
  1118.          * Return a description of the specified action of the object.
  1119.          *
  1120.          * @param i zero-based index of the actions
  1121.          */
  1122.         public String getAccessibleActionDescription(int i) {
  1123.             if (i == 0) {
  1124.                 // [[[PENDING:  WDW -- need to provide a localized string]]]
  1125.                 return new String("click");
  1126.             } else {
  1127.                 return null;
  1128.             }
  1129.         }
  1130.     
  1131.         /**
  1132.          * Perform the specified Action on the object
  1133.          *
  1134.          * @param i zero-based index of actions
  1135.          * @return true if the the action was performed; else false.
  1136.          */
  1137.         public boolean doAccessibleAction(int i) {
  1138.             if (i == 0) {
  1139.                 doClick();
  1140.                 return true;
  1141.             } else {
  1142.                 return false;
  1143.             }
  1144.         }
  1145.  
  1146.         /**
  1147.          * Get the value of this object as a Number.
  1148.          *
  1149.          * @return An Integer of 0 if this isn't selected or an Integer of 1 if
  1150.          * this is selected.
  1151.          * @see AbstractButton#isSelected
  1152.          */
  1153.         public Number getCurrentAccessibleValue() {
  1154.             if (isSelected()) {
  1155.                 return new Integer(1);
  1156.             } else {
  1157.                 return new Integer(0);
  1158.             }
  1159.         }
  1160.  
  1161.         /**
  1162.          * Set the value of this object as a Number.
  1163.          *
  1164.          * @return True if the value was set.
  1165.          */
  1166.         public boolean setCurrentAccessibleValue(Number n) {
  1167.             if (n instanceof Integer) {
  1168.                 int i = n.intValue();
  1169.                 if (i == 0) {
  1170.                     setSelected(false);
  1171.                 } else {
  1172.                     setSelected(true);
  1173.                 }
  1174.                 return true;
  1175.             } else {
  1176.                 return false;
  1177.             }
  1178.         }
  1179.  
  1180.         /**
  1181.          * Get the minimum value of this object as a Number.
  1182.          *
  1183.          * @return An Integer of 0.
  1184.          */
  1185.         public Number getMinimumAccessibleValue() {
  1186.             return new Integer(0);
  1187.         }
  1188.  
  1189.         /**
  1190.          * Get the maximum value of this object as a Number.
  1191.          *
  1192.          * @return An Integer of 1.
  1193.          */
  1194.         public Number getMaximumAccessibleValue() {
  1195.             return new Integer(1);
  1196.         }
  1197.     }
  1198. }
  1199.  
  1200.  
  1201.